home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / network / manageme / tcpdump-.7 / tcpdump- / tcpdump-richard-1.7 / libpcap-0.0 / pcap-bpf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-12  |  5.5 KB  |  237 lines

  1. /*
  2.  * Copyright (c) 1993, 1994
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that: (1) source code distributions
  7.  * retain the above copyright notice and this paragraph in its entirety, (2)
  8.  * distributions including binary code include the above copyright notice and
  9.  * this paragraph in its entirety in the documentation or other materials
  10.  * provided with the distribution, and (3) all advertising materials mentioning
  11.  * features or use of this software display the following acknowledgement:
  12.  * ``This product includes software developed by the University of California,
  13.  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
  14.  * the University nor the names of its contributors may be used to endorse
  15.  * or promote products derived from this software without specific prior
  16.  * written permission.
  17.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  18.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  19.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  20.  */
  21. #ifndef lint
  22. static  char rcsid[] =
  23.     "@(#)$Header: pcap-bpf.c,v 1.14 94/06/03 19:58:49 leres Exp $ (LBL)";
  24. #endif
  25.  
  26. #include <stdio.h>
  27. #include <netdb.h>
  28. #include <ctype.h>
  29. #include <signal.h>
  30. #include <errno.h>
  31. #include <sys/param.h>            /* optionally get BSD define */
  32. #include <sys/time.h>
  33. #include <sys/timeb.h>
  34. #include <sys/socket.h>
  35. #include <sys/file.h>
  36. #include <sys/ioctl.h>
  37. #include <net/bpf.h>
  38. #include <net/if.h>
  39. #include <string.h>
  40.  
  41. #include "pcap-int.h"
  42.  
  43. int
  44. pcap_stats_live(pcap_t *p, struct pcap_stat *ps)
  45. {
  46.     struct bpf_stat s;
  47.  
  48.     if (ioctl(p->fd, BIOCGSTATS, &s) < 0) {
  49.         sprintf(p->errbuf, "BIOCGSTATS: %s", pcap_strerror(errno));
  50.         return (-1);
  51.     }
  52.  
  53.     ps->ps_recv = s.bs_recv;
  54.     ps->ps_drop = s.bs_drop;
  55.     return (0);
  56. }
  57.  
  58. int
  59. pcap_read_live(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
  60. {
  61.     int cc;
  62.     int n = 0;
  63.     register u_char *bp, *ep;
  64.  
  65.  again:
  66.     cc = p->cc;
  67.     if (p->cc == 0) {
  68.         cc = read(p->fd, (char *)p->buffer, p->bufsize);
  69.         if (cc < 0) {
  70.             /* Don't choke when we get ptraced */
  71.             switch (errno) {
  72.  
  73.             case EINTR:
  74.                 goto again;
  75.  
  76.             case EWOULDBLOCK:
  77.                 return (0);
  78. #if defined(sun) && !defined(BSD)
  79.             /*
  80.              * Due to a SunOS bug, after 2^31 bytes, the kernel
  81.              * file offset overflows and read fails with EINVAL.
  82.              * The lseek() to 0 will fix things.
  83.              */
  84.             case EINVAL:
  85.                 if ((long)(tell(p->fd) + p->bufsize) < 0) {
  86.                     (void)lseek(p->fd, 0, 0);
  87.                     goto again;
  88.                 }
  89.                 /* fall through */
  90. #endif
  91.             }
  92.             sprintf(p->errbuf, "read: %s", pcap_strerror(errno));
  93.             return (-1);
  94.         }
  95.         bp = p->buffer;
  96.     } else
  97.         bp = p->bp;
  98.  
  99.     /*
  100.      * Loop through each packet.
  101.      */
  102. #define bhp ((struct bpf_hdr *)bp)
  103.     ep = bp + cc;
  104.     while (bp < ep) {
  105.         register int caplen, hdrlen;
  106.         struct pcap_hdr hdr;
  107.  
  108.         caplen = bhp->bh_caplen;
  109.         hdrlen = bhp->bh_hdrlen;
  110.         hdr.ts = bhp->bh_tstamp;
  111.         hdr.caplen = bhp->bh_caplen;
  112.         hdr.len = bhp->bh_datalen;
  113.         hdr.drops = 0;
  114.         (*callback)(user, &hdr, bp + hdrlen);
  115.         bp += BPF_WORDALIGN(caplen + hdrlen);
  116.         if (++n >= cnt && cnt > 0) {
  117.             p->bp = bp;
  118.             p->cc = ep - bp;
  119.             return (n);
  120.         }
  121.     }
  122. #undef bhp
  123.     p->cc = 0;
  124.     return (n);
  125. }
  126.  
  127. static inline int
  128. bpf_open(pcap_t *p, char *errbuf)
  129. {
  130.     int fd;
  131.     int n = 0;
  132.     char device[sizeof "/dev/bpf000"];
  133.  
  134.     /*
  135.      * Go through all the minors and find one that isn't in use.
  136.      */
  137.     do {
  138.         (void)sprintf(device, "/dev/bpf%d", n++);
  139.         fd = open(device, O_RDONLY);
  140.     } while (fd < 0 && errno == EBUSY);
  141.  
  142.     /*
  143.      * XXX better message for all minors used
  144.      */
  145.     if (fd < 0)
  146.         sprintf(errbuf, "%s: %s", device, pcap_strerror(errno));
  147.  
  148.     return (fd);
  149. }
  150.  
  151. pcap_t *
  152. pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
  153. {
  154.     int fd;
  155.     struct ifreq ifr;
  156.     struct bpf_version bv;
  157.     u_int v;
  158.     pcap_t *p;
  159.  
  160.     p = (pcap_t *)malloc(sizeof(*p));
  161.     if (p == NULL) {
  162.         sprintf(ebuf, "malloc: %s", pcap_strerror(errno));
  163.         return (NULL);
  164.     }
  165.     bzero(p, sizeof(*p));
  166.     fd = bpf_open(p, ebuf);
  167.     if (fd < 0)
  168.         goto bad;
  169.  
  170.     p->fd = fd;
  171.     p->snapshot = snaplen;
  172.  
  173.     if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) {
  174.         sprintf(ebuf, "BIOCVERSION: %s", pcap_strerror(errno));
  175.         goto bad;
  176.     }
  177.     if (bv.bv_major != BPF_MAJOR_VERSION ||
  178.         bv.bv_minor < BPF_MINOR_VERSION) {
  179.         sprintf(ebuf, "kernel bpf filter out of date");
  180.         goto bad;
  181.     }
  182.     (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
  183.     if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
  184.         sprintf(ebuf, "%s: %s", device, pcap_strerror(errno));
  185.         goto bad;
  186.     }
  187.     /* Get the data link layer type. */
  188.     if (ioctl(fd, BIOCGDLT, (caddr_t)&v) < 0) {
  189.         sprintf(ebuf, "BIOCGDLT: %s", pcap_strerror(errno));
  190.         goto bad;
  191.     }
  192.     p->linktype = v;
  193.  
  194.     /* set timeout */
  195.     if (to_ms != 0) {
  196.         struct timeval to;
  197.         to.tv_sec = to_ms / 1000;
  198.         to.tv_usec = (to_ms * 1000) % 1000000;
  199.         if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&to) < 0) {
  200.             sprintf(ebuf, "BIOCSRTIMEOUT: %s",
  201.                 pcap_strerror(errno));
  202.             goto bad;
  203.         }
  204.     }
  205.     if (promisc)
  206.         /* set promiscuous mode, okay if it fails */
  207.         (void)ioctl(p->fd, BIOCPROMISC, NULL);
  208.  
  209.     if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) {
  210.         sprintf(ebuf, "BIOCGBLEN: %s", pcap_strerror(errno));
  211.         goto bad;
  212.     }
  213.     p->bufsize = v;
  214.     p->buffer = (u_char*)malloc(p->bufsize);
  215.     if (p->buffer == NULL) {
  216.         sprintf(ebuf, "malloc: %s", pcap_strerror(errno));
  217.         goto bad;
  218.     }
  219.  
  220.     return (p);
  221.  bad:
  222.     free(p);
  223.     return (NULL);
  224. }
  225.  
  226. int
  227. pcap_setfilter_live(pcap_t *p, struct bpf_program *fp)
  228. {
  229.     if (p->rf.rfile != NULL)
  230.         p->fcode = *fp;
  231.     else if (ioctl(p->fd, BIOCSETF, (caddr_t)fp) < 0) {
  232.         sprintf(p->errbuf, "BIOCSETF: %s", pcap_strerror(errno));
  233.         return (-1);
  234.     }
  235.     return (0);
  236. }
  237.